﻿using System;
using System.Collections.Generic;
using System.Text;

using PlayerMap = System.Collections.Generic.Dictionary<int, WorldObject.PlayerObject>;
using NpcMap = System.Collections.Generic.Dictionary<int, WorldObject.NpcObject>;
using MonsterMap = System.Collections.Generic.Dictionary<int, WorldObject.MonsterObject>;

/**
*@file       gameworld.cs
*@brief      game world stuff
*
*@author     graywind
*@version    1.0.0.1
*@data       2012/02/26
*/

public class GameWorldInitializer
{
    /// <summary>
    /// override this function later
    /// </summary>
    protected virtual void DoInit()
    {

    }
}

public partial class GameWorld : GameWorldInitializer
{
    #region private variable
    //player objects
    private PlayerMap  m_mapPlayer      = new PlayerMap();
    //objects of all npc
    private NpcMap     m_mapNpc         = new NpcMap();
    //objects of all monster
    private MonsterMap m_mapMonster     = new MonsterMap();
    #endregion

    #region events
    //define delegate type when player enter the world
    public delegate void PlayerEnter(WorldObject.PlayerObject playerObj);
    //define the event when player enter the world
    private event PlayerEnter m_playerEnterEvent;
    /// <summary>
    /// define the event when player enter the world
    /// </summary>
    public PlayerEnter PlayerEnterEvent
    {
        get
        {
            return m_playerEnterEvent;
        }
        set
        {
            m_playerEnterEvent = value;
        }
    }

    //define delegate type when player leave the world
    public delegate void PlayerLeave(WorldObject.PlayerObject playerObj);
    //define the event when player leave the world
    private event PlayerLeave m_playerLeaveEvent;
    /// <summary>
    /// define the event when player leave the world
    /// </summary>
    public PlayerLeave PlayerLeaveEvent
    {
        get
        {
            return m_playerLeaveEvent;
        }
        set
        {
            m_playerLeaveEvent = value;
        }
    }

    //define delegate type when player change the world
    public delegate void PlayerWorldChange(WorldObject.PlayerObject playerObj, int world_id);
    //define the event when player change the world
    private event PlayerWorldChange m_playerWorldChangeEvent;
    /// <summary>
    /// define the event when player change the world
    /// </summary>
    public PlayerWorldChange PlayerWorldChangeEvent
    {
        get
        {
            return m_playerWorldChangeEvent;
        }
        set
        {
            m_playerWorldChangeEvent = value;
        }
    }

    //define delegate type when npc enter the world
    public delegate void NpcEnter(WorldObject.NpcObject npcObj);
    //define the event when npc enter the world
    private event NpcEnter m_npcEnterEvent;
    /// <summary>
    /// define the event when npc enter the world
    /// </summary>
    public NpcEnter NpcEnterEvent
    {
        get
        {
            return m_npcEnterEvent;
        }
        set
        {
            m_npcEnterEvent = value;
        }
    }

    //define delegate type when npc leave the world
    public delegate void NpcLeave(WorldObject.NpcObject npcObj);
    //define the event when npc leave the world
    private event NpcLeave m_npcLeaveEvent;
    /// <summary>
    /// define the event when npc leave the world
    /// </summary>
    public NpcLeave NpcLeaveEvent
    {
        get
        {
            return m_npcLeaveEvent;
        }
        set
        {
            m_npcLeaveEvent = value;
        }
    }

    //define delegate type when monster enter the world
    public delegate void MonsterEnter(WorldObject.MonsterObject monObj);
    //define the event when npc enter the world
    private event MonsterEnter m_monsterEnterEvent;
    /// <summary>
    /// define the event when npc enter the world
    /// </summary>
    public MonsterEnter MonsterEnterEvent
    {
        get
        {
            return m_monsterEnterEvent;
        }
        set
        {
            m_monsterEnterEvent = value;
        }
    }

    //define delegate type when monster leave the world
    public delegate void MonsterLeave(WorldObject.MonsterObject monObj);
    //define the event when monster leave the world
    private event MonsterLeave m_monsterLeaveEvent;
    /// <summary>
    /// define the event when monster leave the world
    /// </summary>
    public MonsterLeave MonsterLeaveEvent
    {
        get
        {
            lock (m_monsterLeaveEvent)
            {
                return m_monsterLeaveEvent;
            }
        }
        set
        {
            lock (m_monsterLeaveEvent)
            {
                m_monsterLeaveEvent = value;
            }
        }
    }
    #endregion

    #region property
    //world identifier
    private int m_id;
    /// <summary>
    /// world identifier(read only)
    /// </summary>
    public int WorldId
    {
        get
        {
            return m_id;
        }
        private set
        {
            m_id = value;
        }
    }
    #endregion

    #region private call
    /// <summary>
    /// load configure
    /// </summary>
    /// <param name="world_id"></param>
    /// <param name="config_file"></param>
    void LoadConfig(int world_id, string config_file)
    {

    }
    #endregion

    #region constructor
    /// <summary>
    /// constructor
    /// </summary>
    /// <param name="world_id"></param>
    private GameWorld(int world_id)
    {
        WorldId = world_id;

        DoInit();
    }
    #endregion

    #region static call
    /// <summary>
    /// create a instance
    /// </summary>
    /// <param name="world_id"></param>
    /// <param name="config_file"></param>
    /// <returns></returns>
    public static GameWorld CreateWorld(int world_id, string config_file)
    {
        GameWorld gw = new GameWorld(world_id);
        gw.LoadConfig(world_id, config_file);
        return gw;
    }

    /// <summary>
    /// create logic object of player
    /// </summary>
    /// <param name="detail"></param>
    /// <returns></returns>
    public static WorldObject.PlayerObject CreatePlayerObject(objectinfo.RoleInfoDetail detail, int gate_code)
    {
        objectinfo.LogicObject logicPlayer = new objectinfo.LogicObject();
        logicPlayer.ObjectType = objectinfo.LogicObject.eObjectType.Object_Player;
        logicPlayer.ObjectName = detail.RoleName;
        logicPlayer.Pos = detail.DetailData.Pos;
        logicPlayer.Dir = detail.DetailData.Dir;
        logicPlayer.Level = detail.Level;
        logicPlayer.WorldId = detail.WorldId;
        logicPlayer.GraphicsId = detail.DetailData.GraphicsId;
        logicPlayer.Hp = detail.DetailData.Hp;
        logicPlayer.MaxHp = detail.DetailData.MaxHp;
        logicPlayer.Mp = detail.DetailData.Mp;
        logicPlayer.MaxMp = detail.DetailData.MaxMp;
        logicPlayer.ObjectId = gate_code;

        WorldObject.PlayerObject playerObj = new WorldObject.PlayerObject(logicPlayer, detail);
        return playerObj;
    }

    /// <summary>
    /// create a logic object of npc
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public static WorldObject.NpcObject CreateNpcObject(WorldObject.NpcData data)
    {
        objectinfo.LogicObject logicNpc = new objectinfo.LogicObject();
        WorldObject.NpcObject npcObj = new WorldObject.NpcObject(logicNpc, data);
        return npcObj;
    }

    /// <summary>
    /// create a logic object of monster
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public static WorldObject.MonsterObject CreateMonsterObject(WorldObject.MonsterData data)
    {
        objectinfo.LogicObject logicMonster = new objectinfo.LogicObject();
        WorldObject.MonsterObject monsterObj = new WorldObject.MonsterObject(logicMonster, data);
        return monsterObj;
    }
    #endregion

    #region external call
    /// <summary>
    /// add a player into this world
    /// </summary>
    /// <param name="detail"></param>
    /// <returns></returns>
    public bool Add(WorldObject.PlayerObject obj)
    {
        lock (m_mapPlayer)
        {
            if (!m_mapPlayer.ContainsKey(obj.ObjectInfo.ObjectId))
            {
                m_mapPlayer.Add(obj.ObjectInfo.ObjectId, obj);

                if (PlayerEnterEvent != null)
                    PlayerEnterEvent(obj);

                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// add a npc into this world
    /// </summary>
    /// <param name="npcdata"></param>
    /// <returns></returns>
    public bool Add(WorldObject.NpcObject obj)
    {
        lock (m_mapNpc)
        {
            if (!m_mapNpc.ContainsKey(obj.ObjectInfo.ObjectId))
            {
                m_mapNpc.Add(obj.ObjectInfo.ObjectId, obj);

                if (NpcEnterEvent != null)
                    NpcEnterEvent(obj);

                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// add a monster into this world
    /// </summary>
    /// <param name="monsterObj"></param>
    /// <returns></returns>
    public bool Add(WorldObject.MonsterObject obj)
    {
        lock (m_mapMonster)
        {
            if (!m_mapMonster.ContainsKey(obj.ObjectInfo.ObjectId))
            {
                m_mapMonster.Add(obj.ObjectInfo.ObjectId, obj);

                if (MonsterEnterEvent != null)
                    MonsterEnterEvent(obj);

                return true;
            }
        }
        return false;
    }

    /// <summary>
    /// get a player object in this world
    /// </summary>
    /// <param name="ObjectId"></param>
    /// <returns></returns>
    public WorldObject.PlayerObject GetPlayer(int ObjectId)
    {
        lock (m_mapPlayer)
        {
            WorldObject.PlayerObject obj;
            if (m_mapPlayer.TryGetValue(ObjectId, out obj))
                return obj;
        }

        return null;
    }

    /// <summary>
    /// get a npc object in this world
    /// </summary>
    /// <param name="ObjectId"></param>
    /// <returns></returns>
    public WorldObject.NpcObject GetNpc(int ObjectId)
    {
        lock (m_mapNpc)
        {
            WorldObject.NpcObject obj;
            if (m_mapNpc.TryGetValue(ObjectId, out obj))
                return obj;
        }

        return null;
    }

    /// <summary>
    /// get a monster object in this world
    /// </summary>
    /// <param name="ObjectId"></param>
    /// <returns></returns>
    public WorldObject.MonsterObject GetMonster(int ObjectId)
    {
        lock (m_mapMonster)
        {
            WorldObject.MonsterObject obj;
            if (m_mapMonster.TryGetValue(ObjectId, out obj))
                return obj;
        }

        return null;
    }

    /// <summary>
    /// remove a object of player type
    /// </summary>
    /// <param name="obj"></param>
    public void Remove(WorldObject.PlayerObject obj)
    {
        lock (m_mapPlayer)
        {
            if (m_mapPlayer.ContainsKey(obj.ObjectInfo.ObjectId))
            {
                m_mapPlayer.Remove(obj.ObjectInfo.ObjectId);
                if (PlayerLeaveEvent != null)
                    PlayerLeaveEvent(obj);
            }
        }
    }

    /// <summary>
    /// remove a object of npc type
    /// </summary>
    /// <param name="obj"></param>
    public void Remove(WorldObject.NpcObject obj)
    {
        lock (m_mapNpc)
        {
            if (m_mapNpc.ContainsKey(obj.ObjectInfo.ObjectId))
            {
                m_mapNpc.Remove(obj.ObjectInfo.ObjectId);
                if (NpcLeaveEvent != null)
                    NpcLeaveEvent(obj);
            }
        }
    }


    /// <summary>
    /// remove a object of monster type
    /// </summary>
    /// <param name="obj"></param>
    public void Remove(WorldObject.MonsterObject obj)
    {
        lock (m_mapMonster)
        {
            if (m_mapMonster.ContainsKey(obj.ObjectInfo.ObjectId))
            {
                m_mapMonster.Remove(obj.ObjectInfo.ObjectId);
                if (MonsterLeaveEvent != null)
                    MonsterLeaveEvent(obj);
            }
        }
    }

    /// <summary>
    /// change the world
    /// </summary>
    /// <param name="obj"></param>
    public void WorldChange(WorldObject.PlayerObject obj ,int world_id)
    {
        lock (m_mapPlayer)
        {
            if (m_mapPlayer.ContainsKey(obj.ObjectInfo.ObjectId))
            {
                obj.ObjectInfo.WorldId = world_id;
                obj.PlayerDetail.WorldId = world_id;

                m_mapPlayer.Remove(obj.ObjectInfo.ObjectId);
                if (m_playerWorldChangeEvent != null)
                    m_playerWorldChangeEvent(obj, world_id);
            }
        }
    }
    #endregion
}